package com.test.springboot.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.test.springboot.config.RedissonConfig;
import com.test.springboot.domain.Stock;
import com.test.springboot.mapper.StockMappper;
import lombok.Synchronized;
import org.apache.commons.lang.StringUtils;
import org.checkerframework.checker.signature.qual.PolySignature;
import org.junit.Test;
import org.redisson.Redisson;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;


@Service
//@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS )
public class StockService {
    @Autowired
    private StockMappper stockMappper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    //
    @Autowired
    private RedissonClient redissonClient;

//    CountDownLatch countDownLatch = new CountDownLatch(6);

    public void testLatch() {
        RCountDownLatch cdl = this.redissonClient.getCountDownLatch("cdl");
        try {
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("班长锁门");
    }

    public void testCountDown() {
        RCountDownLatch cdl = this.redissonClient.getCountDownLatch("cdl");
        cdl.trySetCount(6);
        cdl.countDown();
        System.out.println("一位同学出门");
    }


    //直接在浏览器上请求读锁和写锁
    public void testReadLock() {
        RReadWriteLock rwLock = this.redissonClient.getReadWriteLock("RWLock");
        rwLock.readLock().lock(10, TimeUnit.SECONDS);
    }

    public void testWriterLock() {
        RReadWriteLock rwLock = this.redissonClient.getReadWriteLock("RWLock");
        rwLock.writeLock().lock(10, TimeUnit.SECONDS);
    }

    //全局变量
    Semaphore semaphore = new Semaphore(3);

    public void testSemaphore() {
        try {
            semaphore.acquire();
            System.out.println("1入场。 " + Thread.currentThread().getName());
            TimeUnit.SECONDS.sleep(new Random().nextInt(5));
            semaphore.release();
            System.out.println("1离场。 " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void testRsemaphore() {
        RSemaphore rsemaphore = this.redissonClient.getSemaphore("Rsemaphore");
        rsemaphore.trySetPermits(3);
        try {
            rsemaphore.acquire();
            System.out.println("10086入场"+Thread.currentThread().getName());
            this.redisTemplate.opsForList().rightPush("log","10086入场"+Thread.currentThread().getName());
            TimeUnit.SECONDS.sleep(3);
            rsemaphore.release();
            System.out.println("10086离场"+Thread.currentThread().getName());
            this.redisTemplate.opsForList().rightPush("log","10086入场"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public void testFairLock(Long id) {
        RLock fairLock = this.redissonClient.getLock("fairLock");
        fairLock.lock();
        try {
            TimeUnit.SECONDS.sleep(10);
            System.out.println("测试公平锁" + id);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            fairLock.unlock();
        }

    }

    public void deduct() {
        RLock lock = this.redissonClient.getLock("lock");
        lock.lock();
        try {
            String stock = this.redisTemplate.opsForValue().get("stock");
            //3.设置库存值
            if (stock != null && stock.length() != 0) {
//            redisTemplate.opsForValue().decrement("stock");
                Integer st = Integer.valueOf(stock);
                if (st > 0) {
                    this.redisTemplate.opsForValue().set("stock", String.valueOf(--st));
                }
            }
            this.test();
//            try {
//                TimeUnit.SECONDS.sleep(500);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
        } finally {
            lock.unlock();

        }
    }

    public void test() {
        RLock lock1 = this.redissonClient.getLock("lock");
        lock1.lock();
        System.out.println("测试可重入锁......");
        lock1.unlock();
    }

    public void deduct5() {
        String uuid = UUID.randomUUID().toString();
        while (!this.redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3, TimeUnit.SECONDS)) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //1查询库存
        //2.判断
        try {
            String stock = this.redisTemplate.opsForValue().get("stock");
            //3.设置库存值
            if (stock != null && stock.length() != 0) {
//            redisTemplate.opsForValue().decrement("stock");
                Integer st = Integer.valueOf(stock);
                if (st > 0) {
                    this.redisTemplate.opsForValue().set("stock", String.valueOf(--st));
                }
            }
        } finally {
            //判断是自己就爱的锁再删除
            if (StringUtils.equals(this.redisTemplate.opsForValue().get("lock"), uuid)) {
                this.redisTemplate.delete("lock");
            }

        }
    }

    //@Transactional
    public void deduct4() {
        //查询库存信息
        List<Stock> productCode = stockMappper.selectList(new QueryWrapper<Stock>().eq("product_code", "1001"));
        //这里取第一个库
        Stock stock = productCode.get(0);
        //判断库存是否充足
        if (stock != null && stock.getCount() > 0) {
            //每次查询库存减1 版本加1
            stock.setCount(stock.getCount() - 1);
            Integer version = stock.getVersion();
            stock.setVersion(version + 1);
            //筛选条件确定结果
            if (stockMappper.update(stock, new QueryWrapper<Stock>().eq("id", stock.getId()).eq("version", version)) == 0) {
                //如果跟新失败，则重试！
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.deduct4();
            }
        }
    }


    //    private Stock stock = new Stock();
//    ReentrantLock lock = new ReentrantLock();
//    @Transactional
    public void deduct2() {
//        lock.lock();

        try {
//            QueryWrapper<Stock> queryWrapper = new QueryWrapper<>();
//            queryWrapper.eq("product_code","1001");
//            Stock stock = stockMappper.selectOne(queryWrapper);
//            if(stock != null && stock.getCount()>0) {
//                stock.setCount(stock.getCount()-1);
//                stockMappper.updateById(stock);
//                System.out.println("库存容量为"+stock.getCount());
            stockMappper.updateStock("1001", 1);
        } finally {
//            lock.unlock();
        }
    }

    @Transactional
    public void deduct3() {
        List<Stock> stocks = stockMappper.queryStock("1001");
        Stock stock = stocks.get(0);
        if (stock != null && stock.getCount() > 0) {
            stock.setCount(stock.getCount() - 1);
            stockMappper.updateById(stock);
        }
    }
}
